home *** CD-ROM | disk | FTP | other *** search
/ PC World 2008 September / PCWorld_2008-09_cd.bin / v cisle / sadanastroju / lightning-0.8-tb-win.xpi / chrome / calendar.jar / content / calendar / calendar-event-dialog.js < prev    next >
Text File  |  2008-02-02  |  43KB  |  1,229 lines

  1. /* -*- Mode: javascript; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
  2. /* ***** BEGIN LICENSE BLOCK *****
  3.  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  4.  *
  5.  * The contents of this file are subject to the Mozilla Public License Version
  6.  * 1.1 (the "License"); you may not use this file except in compliance with
  7.  * the License. You may obtain a copy of the License at
  8.  * http://www.mozilla.org/MPL/
  9.  *
  10.  * Software distributed under the License is distributed on an "AS IS" basis,
  11.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12.  * for the specific language governing rights and limitations under the
  13.  * License.
  14.  *
  15.  * The Original Code is Oracle Corporation code.
  16.  *
  17.  * The Initial Developer of the Original Code is Oracle Corporation
  18.  * Portions created by the Initial Developer are Copyright (C) 2005
  19.  * the Initial Developer. All Rights Reserved.
  20.  *
  21.  * Contributor(s):
  22.  *   Stuart Parmenter <stuart.parmenter@oracle.com>
  23.  *   Joey Minta <jminta@gmail.com>
  24.  *
  25.  * Alternatively, the contents of this file may be used under the terms of
  26.  * either the GNU General Public License Version 2 or later (the "GPL"), or
  27.  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  28.  * in which case the provisions of the GPL or the LGPL are applicable instead
  29.  * of those above. If you wish to allow use of your version of this file only
  30.  * under the terms of either the GPL or the LGPL, and not to allow others to
  31.  * use your version of this file under the terms of the MPL, indicate your
  32.  * decision by deleting the provisions above and replace them with the notice
  33.  * and other provisions required by the GPL or the LGPL. If you do not delete
  34.  * the provisions above, a recipient may use your version of this file under
  35.  * the terms of any one of the MPL, the GPL or the LGPL.
  36.  *
  37.  * ***** END LICENSE BLOCK ***** */
  38.  
  39. var gReadOnlyMode = false;
  40.  
  41. // If the user clicks 'More', then we set this to true.  Otherwise, we don't
  42. // load/check the stuff in this area, because it hasn't changed.
  43. var gDetailsShown = false;
  44.  
  45. var gItemDuration;
  46.  
  47. /* dialog stuff */
  48. function onLoad()
  49. {
  50.     var args = window.arguments[0];
  51.  
  52.     window.onAcceptCallback = args.onOk;
  53.     window.calendarItem = args.calendarEvent;
  54.     window.originalItem = args.calendarEvent;
  55.     window.mode = args.mode;
  56.     window.recurrenceInfo = null;
  57.  
  58.     // the calling entity provides us with an object that is responsible
  59.     // for recording details about the initiated modification. the 'finalize'-property
  60.     // is our hook in order to receive a notification in case the operation needs
  61.     // to be terminated prematurely. this function will be called if the calling
  62.     // entity needs to immediately terminate the pending modification. in this
  63.     // case we serialize the item and close the window.
  64.     if (args.job) {
  65.  
  66.         // keep this context...
  67.         var self = this;
  68.  
  69.         // store the 'finalize'-functor in the provided job-object.
  70.         args.job.finalize = function finalize() {
  71.  
  72.             // store any pending modifications...
  73.             self.onAccept();
  74.  
  75.             var item = window.calendarItem;
  76.  
  77.             // ...and close the window.
  78.             window.close();
  79.  
  80.             return item;
  81.         }
  82.     }
  83.  
  84.     if (window.calendarItem.calendar && window.calendarItem.calendar.readOnly
  85.         && window.mode != "new") {
  86.         gReadOnlyMode = true;
  87.     }
  88.  
  89.     /* add calendars to the calendar menulist */
  90.     var calendarList = document.getElementById("item-calendar");
  91.     var calendars = getCalendarManager().getCalendars({});
  92.     for (i in calendars) {
  93.         var calendar = calendars[i];
  94.         var menuitem = calendarList.appendItem(calendar.name, i);
  95.         menuitem.calendar = calendar;
  96.     }
  97.  
  98.     document.getElementById("send-invitations-checkbox").collapsed = isSunbird();
  99.  
  100.     loadDialog(window.calendarItem);
  101.  
  102.     // figure out what the title of the dialog should be and set it
  103.     updateTitle();
  104.  
  105.     // hide rows based on if this is an event or todo
  106.     updateStyle();
  107.  
  108.     // update the accept button
  109.     updateAccept();
  110.  
  111.     // update datetime pickers
  112.     updateDueDate();
  113.     updateEntryDate();
  114.  
  115.     // update datetime pickers
  116.     updateAllDay();
  117.  
  118.     // update recurrence button
  119.     updateRecurrence();
  120.  
  121.     // update our size!
  122.     window.sizeToContent();
  123.  
  124.     document.getElementById("item-title").focus();
  125.  
  126.     opener.setCursor("auto");
  127. }
  128.  
  129. function dispose()
  130. {
  131.     var args = window.arguments[0];
  132.     if(args.job && args.job.dispose)
  133.       args.job.dispose();
  134. }
  135.  
  136. function onAccept()
  137. {
  138.     // we need to clone the item in order to apply the changes.
  139.     // it is important to not apply the changes to the original item
  140.     // (even if it happens to be mutable) in order to guarantee
  141.     // that providers see a proper oldItem/newItem pair in case
  142.     // they rely on this fact (e.g. WCAP does).
  143.     var originalItem = window.calendarItem;
  144.     var item = originalItem.clone();
  145.  
  146.     saveDialog(item);
  147.  
  148.     var calendar = document.getElementById("item-calendar").selectedItem.calendar;
  149.  
  150.     window.onAcceptCallback(item, calendar, window.originalItem);
  151.  
  152.     // We already set persist="collapsed" in the xul file, but because
  153.     // of a bug on 1_8_BRANCH we need this to make it really persist.
  154.     document.persist("description-row", "collapsed");
  155.  
  156.     dispose();
  157.  
  158.     window.calendarItem = item;
  159.  
  160.     return true;
  161. }
  162.  
  163. function onCancel()
  164. {
  165.     dispose();
  166. }
  167.  
  168. function loadDialog(item)
  169. {
  170.     var kDefaultTimezone = window.opener.calendarDefaultTimezone();
  171.  
  172.     setElementValue("item-title",       item.title);
  173.     setElementValue("item-location",    item.getProperty("LOCATION"));
  174.  
  175.     /* event specific properties */
  176.     if (isEvent(item)) {
  177.         var startDate = item.startDate.getInTimezone(kDefaultTimezone);
  178.         var endDate = item.endDate.getInTimezone(kDefaultTimezone);
  179.         gItemDuration = endDate.subtractDate(startDate);
  180.         
  181.         // Check if an all-day event has been passed in (to adapt endDate).
  182.         if (startDate.isDate) {
  183.             setElementValue("event-all-day", true, "checked");
  184.             endDate.day -= 1;
  185.             gItemDuration.days -= 1;
  186.         }
  187.         
  188.         setElementValue("event-starttime",   startDate.jsDate);
  189.         setElementValue("event-endtime",     endDate.jsDate);
  190.         document.getElementById("component-type").selectedIndex = 0;
  191.     }
  192.  
  193.     /* todo specific properties */
  194.     if (isToDo(item)) {
  195.         var entryDate;
  196.         var hasEntryDate = (item.entryDate != null);
  197.         setElementValue("todo-has-entrydate", hasEntryDate, "checked");
  198.         if (hasEntryDate) {
  199.             entryDate = item.entryDate.getInTimezone(kDefaultTimezone);
  200.             setElementValue("todo-entrydate", entryDate.jsDate);
  201.         }
  202.  
  203.         var dueDate;
  204.         var hasDueDate = (item.dueDate != null);
  205.         setElementValue("todo-has-duedate", hasDueDate, "checked");
  206.         if (hasDueDate) {
  207.             dueDate = item.dueDate.getInTimezone(kDefaultTimezone);
  208.             setElementValue("todo-duedate", dueDate.jsDate);
  209.         }
  210.         if (hasEntryDate && hasDueDate) {
  211.             gItemDuration = item.dueDate.subtractDate(item.entryDate);
  212.         }
  213.         document.getElementById("component-type").selectedIndex = 1;
  214.     }
  215.  
  216.     /* item default calendar */
  217.     // If this is a new item, it might not have a calendar, but a default
  218.     // option could well have been passed in.
  219.     var calendarToUse = item.calendar || window.arguments[0].calendar
  220.     if (calendarToUse) {
  221.         var calendarList = document.getElementById("item-calendar");
  222.         var calendars = getCalendarManager().getCalendars({});
  223.         for (i in calendars) {
  224.             if (calendarToUse.uri.equals(calendars[i].uri))
  225.                 calendarList.selectedIndex = i;
  226.         }
  227.     } else {
  228.         // no calendar attached to item
  229.         // select first entry in calendar list as default
  230.         document.getElementById("item-calendar").selectedIndex = 0;
  231.     }
  232.  
  233.     /* Categories */
  234.     try {
  235.         var categoriesList = getPrefCategoriesArray();
  236.  
  237.         // insert the category already in the menulist so it doesn't get lost
  238.         var itemProperty = item.getProperty("CATEGORIES");
  239.         if (itemProperty) {
  240.             var itemCategories = categoriesStringToArray(itemProperty);
  241.             for each (var itemCategory in itemCategories) {
  242.                 if (!categoriesList.some(function(cat){ return cat == itemCategory; })){
  243.                     categoriesList.push(itemCategory);
  244.                 }
  245.             }
  246.         }
  247.         sortArrayByLocaleCollator(categoriesList);
  248.  
  249.         var oldMenulist = document.getElementById("item-categories");
  250.         while (oldMenulist.hasChildNodes()) {
  251.             oldMenulist.removeChild(oldMenulist.lastChild);
  252.         }
  253.  
  254.         var categoryMenuList = document.getElementById("item-categories");
  255.         var indexToSelect = 0;
  256.  
  257.         // Add a 'none' option to allow users to cancel the category
  258.         var noneItem = categoryMenuList.appendItem(calGetString("calendar", "None"), "NONE");
  259.  
  260.         for (var i in categoriesList) {
  261.             var catItem = categoryMenuList.appendItem(categoriesList[i], categoriesList[i]);
  262.             catItem.value = categoriesList[i];
  263.             if (itemCategory && categoriesList[i] == itemCategory) {
  264.                 indexToSelect = parseInt(i)+1;  // Add 1 because of 'None'
  265.             }
  266.         }
  267.         var newCategory = calGetString("calendar", "newCategory");
  268.         categoryMenuList.appendItem(newCategory, "##NEW");
  269.         categoryMenuList.selectedIndex = indexToSelect;
  270.         gOldCatIndex = indexToSelect;
  271.  
  272.     } catch (ex) {
  273.         // The app using this dialog doesn't support categories
  274.         document.getElementById("categories-box").collapsed = true;
  275.     }
  276.  
  277.  
  278.     /* recurrence */
  279.     /* if the item is a proxy occurrence/instance, a few things aren't valid:
  280.      * - Setting recurrence on the item
  281.      * - changing the calendar
  282.      */
  283.     if (item.parentItem != item) {
  284.         setElementValue("item-recurrence", "true", "disabled");
  285.         setElementValue("set-recurrence", "true", "disabled");
  286.         setElementValue("item-calendar", "true", "disabled");
  287.  
  288.         // don't allow to revoke the entrydate of recurring todo's.
  289.         disableElement("todo-has-entrydate");
  290.     } else if (item.recurrenceInfo)
  291.         setElementValue("item-recurrence", "true", "checked");
  292.  
  293.     /* Alarms */
  294.     if (item.alarmOffset) {
  295.         var alarmRelatedStart = (item.alarmRelated == Components.interfaces.calIItemBase.ALARM_RELATED_START);
  296.         if (alarmRelatedStart) {
  297.             setElementValue("alarm-trigger-relation", "START");
  298.         } else {
  299.             setElementValue("alarm-trigger-relation", "END");
  300.         }
  301.  
  302.         var offset = item.alarmOffset;
  303.         if (offset.minutes) {
  304.             var minutes = offset.minutes + offset.hours*60 + offset.days*24*60 + offset.weeks*60*24*7;
  305.             // Special cases for the common alarms
  306.             if ((minutes == 15) && alarmRelatedStart) {
  307.                 document.getElementById("item-alarm").selectedIndex = 2;
  308.             } else if ((minutes == 30) && alarmRelatedStart) {
  309.                 document.getElementById("item-alarm").selectedIndex = 3;
  310.             } else {
  311.                 setElementValue("alarm-length-field", minutes);
  312.                 setElementValue("alarm-length-units", "minutes");
  313.                 setElementValue("item-alarm", "custom");
  314.             }
  315.         } else if (offset.hours) {
  316.             var hours = offset.hours + offset.days*24 + offset.weeks*24*7;
  317.             setElementValue("alarm-length-field", hours);
  318.             setElementValue("alarm-length-units", "hours");
  319.             setElementValue("item-alarm", "custom");
  320.         } else { // days
  321.             var days = offset.days + offset.weeks*7;
  322.             setElementValue("alarm-length-field", days);
  323.             setElementValue("alarm-length-units", "days");
  324.             setElementValue("item-alarm", "custom");
  325.         }
  326.     }
  327.  
  328.     var detailsButton = document.getElementById("calendar-event-dialog").getButton("disclosure");
  329.     var detailsElements = document.getElementsByAttribute("details", "true");
  330.  
  331.     if (document.getElementById("description-row").getAttribute("collapsed") != "true") {
  332.         detailsButton.setAttribute("label", lessLabel);
  333.         for each (elem in detailsElements) {
  334.             elem.collapsed = false;
  335.         }
  336.         loadDetails();
  337.     } else {
  338.         for each (elem in detailsElements) {
  339.             elem.collapsed = true;
  340.         }
  341.         detailsButton.setAttribute("label", moreLabel);
  342.     }
  343. }
  344.  
  345. function saveDialog(item)
  346. {
  347.     setItemProperty(item, "title",       getElementValue("item-title"));
  348.     setItemProperty(item, "LOCATION",    getElementValue("item-location"));
  349.  
  350.     var kDefaultTimezone = window.opener.calendarDefaultTimezone();
  351.  
  352.     if (isEvent(item)) {
  353.         var startDate = jsDateToDateTime(getElementValue("event-starttime"));
  354.         var endDate = jsDateToDateTime(getElementValue("event-endtime"));
  355.         startDate = startDate.getInTimezone(kDefaultTimezone);
  356.         endDate = endDate.getInTimezone(kDefaultTimezone);
  357.  
  358.         var isAllDay = getElementValue("event-all-day", "checked");
  359.         if (isAllDay) {
  360.             startDate.isDate = true;
  361.  
  362.             endDate.isDate = true;
  363.             endDate.day += 1;
  364.         }
  365.  
  366.         setItemProperty(item, "startDate",   startDate);
  367.         setItemProperty(item, "endDate",     endDate);
  368.     }
  369.  
  370.     if (isToDo(item)) {
  371.         var entryDate = getElementValue("todo-has-entrydate", "checked") ? 
  372.             jsDateToDateTime(getElementValue("todo-entrydate")) : null;
  373.         if (entryDate) {
  374.             entryDate = entryDate.getInTimezone(kDefaultTimezone);
  375.         } else {
  376.             // no entrydate, no recurrence
  377.             item.recurrenceInfo = null;
  378.             window.recurrenceInfo = null;
  379.         }
  380.         setItemProperty(item, "entryDate",   entryDate);
  381.  
  382.         var dueDate = getElementValue("todo-has-duedate", "checked") ? 
  383.             jsDateToDateTime(getElementValue("todo-duedate")) : null;
  384.         if (dueDate) {
  385.             dueDate = dueDate.getInTimezone(kDefaultTimezone);
  386.         }
  387.         setItemProperty(item, "dueDate",     dueDate);
  388.  
  389.         var percentCompleteInteger = 0;
  390.         if (getElementValue("percent-complete-textbox") != "") {
  391.             percentCompleteInteger = parseInt(getElementValue("percent-complete-textbox"));
  392.         }
  393.         if (percentCompleteInteger < 0) {
  394.             percentCompleteInteger = 0;
  395.         } else if (percentCompleteInteger > 100) {
  396.             percentCompleteInteger = 100;
  397.         }
  398.         setItemProperty(item, "PERCENT-COMPLETE", percentCompleteInteger);
  399.     }
  400.  
  401.     /* recurrence */
  402.     if (getElementValue("item-recurrence", "checked")) {
  403.         if (window.recurrenceInfo) {
  404.             item.recurrenceInfo = window.recurrenceInfo;
  405.         }
  406.     } else {
  407.         item.recurrenceInfo = null;
  408.     }
  409.  
  410.     /* Category */
  411.     var category = getElementValue("item-categories");
  412.  
  413.     if (category != "NONE") {
  414.        setItemProperty(item, "CATEGORIES", categoriesArrayToString([category]));
  415.     } else {
  416.        item.deleteProperty("CATEGORIES");
  417.     }
  418.  
  419.     if (!gDetailsShown) {
  420.         // We never showed the items in the 'More' box.  That means that clone()
  421.         // took care of it, so just return now
  422.         dump(item.icalString + '\n');
  423.         return;
  424.     }
  425.  
  426.     setItemProperty(item, "URL",         getElementValue("item-url"));
  427.     setItemProperty(item, "DESCRIPTION", getElementValue("item-description"));
  428.  
  429.     var status;
  430.     if (isEvent(item)) {
  431.         status = getElementValue("event-status");
  432.     } else {
  433.         status = getElementValue("todo-status");
  434.         if (status != "COMPLETED") {
  435.             item.completedDate = null;
  436.         }
  437.     }
  438.  
  439.     setItemProperty(item, "STATUS",   status);
  440.     setItemProperty(item, "PRIORITY", getElementValue("priority-levels"));
  441.     setItemProperty(item, "CLASS", getElementValue("privacy-menulist"));
  442.  
  443.     if (item.status == "COMPLETED" && isToDo(item)) {
  444.         item.completedDate = jsDateToDateTime(getElementValue("completed-date-picker"));
  445.     }
  446.  
  447.     // Attendees
  448.     item.removeAllAttendees();
  449.     var attendeeListBox = document.getElementById("attendees-list");
  450.     for each (att in attendeeListBox.attendees) {
  451.         item.addAttendee(att);
  452.     }
  453.     var sendInvitesCheckbox = document.getElementById("send-invitations-checkbox");
  454.     if (sendInvitesCheckbox.checked) {
  455.         setItemProperty(item, "X-MOZ-SEND-INVITATIONS", "TRUE");
  456.     } else {
  457.         item.deleteProperty("X-MOZ-SEND-INVITATIONS");
  458.     }
  459.  
  460.     /* alarms */
  461.     var hasAlarm = (getElementValue("item-alarm") != "none");
  462.     if (!hasAlarm) {
  463.         item.alarmOffset = null;
  464.         item.alarmLastAck = null;
  465.         item.alarmRelated = null;
  466.     } else {
  467.         var alarmLength = getElementValue("alarm-length-field");
  468.         var alarmUnits = document.getElementById("alarm-length-units").selectedItem.value;
  469.         if (document.getElementById("alarm-trigger-relation").selectedItem.value == "START") {
  470.             item.alarmRelated = Components.interfaces.calIItemBase.ALARM_RELATED_START;
  471.         } else {
  472.             item.alarmRelated = Components.interfaces.calIItemBase.ALARM_RELATED_END;
  473.         }
  474.         var duration = Components.classes["@mozilla.org/calendar/duration;1"]
  475.                                  .createInstance(Components.interfaces.calIDuration);
  476.         if (item.alarmRelated == Components.interfaces.calIItemBase.ALARM_RELATED_START) {
  477.             duration.isNegative = true;
  478.         }
  479.         duration[alarmUnits] = alarmLength;
  480.         duration.normalize();
  481.  
  482.         item.alarmOffset = duration;
  483.     }
  484.  
  485.     dump(item.icalString + "\n");
  486. }
  487.  
  488. function updateTitle()
  489. {
  490.     var isNew = window.calendarItem.isMutable;
  491.     if (isEvent(window.calendarItem)) {
  492.         if (isNew)
  493.             document.title = calGetString("calendar", "newEventDialog");
  494.         else
  495.             document.title = calGetString("calendar", "editEventDialog");
  496.     } else if (isToDo(window.calendarItem)) {
  497.         if (isNew)
  498.             document.title = calGetString("calendar", "newTaskDialog");
  499.         else
  500.             document.title = calGetString("calendar", "editTaskDialog");
  501.     }
  502. }
  503.  
  504. function updateComponentType(aValue) {
  505.     if ((aValue == "event" && isEvent(window.calendarItem)) ||
  506.         (aValue == "todo" && isToDo(window.calendarItem))) {
  507.         return;
  508.     }
  509.     var oldItem = window.calendarItem.clone();
  510.     saveDialog(oldItem);
  511.  
  512.     var newItem;
  513.     if (aValue == "event") {
  514.         newItem = createEvent();
  515.         oldItem.wrappedJSObject.cloneItemBaseInto(newItem.wrappedJSObject);
  516.         newItem.startDate = oldItem.entryDate || now();
  517.         newItem.endDate = oldItem.dueDate || now();
  518.     } else {
  519.         newItem = createTodo();
  520.         oldItem.wrappedJSObject.cloneItemBaseInto(newItem.wrappedJSObject);
  521.         newItem.entryDate = oldItem.startDate;
  522.         newItem.dueDate = oldItem.endDate;
  523.     }
  524.     window.calendarItem = newItem;
  525.  
  526.     loadDialog(newItem);
  527.  
  528.     // remove old style rule, so the hidden stuff comes back
  529.     const kDialogStylesheet = "chrome://calendar/content/calendar-event-dialog.css";
  530.  
  531.     for each(var stylesheet in document.styleSheets) {
  532.         if (stylesheet.href != kDialogStylesheet) {
  533.             continue;
  534.         }
  535.         for (var i=0; i < stylesheet.cssRules.length; i++) {
  536.             if (stylesheet.cssRules[i].selectorText == ".todo-only" ||
  537.                 stylesheet.cssRules[i].selectorText == ".event-only") {
  538.                 stylesheet.deleteRule(i);
  539.                 break;
  540.             } 
  541.         }
  542.         break;
  543.     }
  544.  
  545.     updateStyle();
  546.     updateAccept();
  547.     updateDueDate();
  548.     updateEntryDate();
  549.     updateAllDay();
  550.     updateRecurrence();
  551.  
  552.     window.sizeToContent();
  553. }
  554.  
  555. function updateStyle()
  556. {
  557.     const kDialogStylesheet = "chrome://calendar/content/calendar-event-dialog.css";
  558.  
  559.     for each(var stylesheet in document.styleSheets) {
  560.         if (stylesheet.href == kDialogStylesheet) {
  561.             if (isEvent(window.calendarItem))
  562.                 stylesheet.insertRule(".todo-only { display: none; }", 0);
  563.             else if (isToDo(window.calendarItem))
  564.                 stylesheet.insertRule(".event-only { display: none; }", 0);
  565.             return;
  566.         }
  567.     }
  568. }
  569.  
  570. function onStartTimeChange()
  571. {
  572.     if (!gItemDuration) {
  573.         return;
  574.     }
  575.     var startWidgetId;
  576.     var endWidgetId;
  577.     if (isEvent(window.calendarItem)) {
  578.         startWidgetId = "event-starttime";
  579.         endWidgetId = "event-endtime";
  580.     } else {
  581.         if (!getElementValue("todo-has-entrydate", "checked") || !getElementValue("todo-has-duedate", "checked")) {
  582.             gItemDuration = null;
  583.             return;
  584.         }
  585.         startWidgetId = "todo-entrydate";
  586.         endWidgetId = "todo-duedate";
  587.     }
  588.     var start = jsDateToDateTime(getElementValue(startWidgetId));
  589.     start.addDuration(gItemDuration);
  590.     setElementValue(endWidgetId, start.getInTimezone(window.opener.calendarDefaultTimezone()).jsDate);
  591.     updateAccept();
  592. }
  593.  
  594. function onEndTimeChange()
  595. {
  596.     var startWidgetId;
  597.     var endWidgetId;
  598.     if (isEvent(window.calendarItem)) {
  599.         startWidgetId = "event-starttime";
  600.         endWidgetId = "event-endtime";
  601.     } else {
  602.         if (!getElementValue("todo-has-entrydate", "checked") || 
  603.             !getElementValue("todo-has-duedate", "checked")) {
  604.             gItemDuration = null;
  605.             return;
  606.         }
  607.         startWidgetId = "todo-entrydate";
  608.         endWidgetId = "todo-duedate";
  609.     }
  610.     var start = jsDateToDateTime(getElementValue(startWidgetId));
  611.     var end = jsDateToDateTime(getElementValue(endWidgetId));
  612.     gItemDuration = end.subtractDate(start);
  613.     updateAccept();
  614. }
  615. function updateAccept()
  616. {
  617.     var enableAccept = true;
  618.  
  619.     var kDefaultTimezone = window.opener.calendarDefaultTimezone();
  620.  
  621.     var title = getElementValue("item-title");
  622.     if (title.length == 0)
  623.         enableAccept = false;
  624.  
  625.     // don't allow for end dates to be before start dates
  626.     var startDate;
  627.     var endDate;
  628.     if (isEvent(window.calendarItem)) {
  629.         startDate = jsDateToDateTime(getElementValue("event-starttime"));
  630.         endDate = jsDateToDateTime(getElementValue("event-endtime"));
  631.  
  632.         // For all-day events we are not interested in times and compare only dates.
  633.         if (getElementValue("event-all-day", "checked")) {
  634.             // jsDateToDateTime returnes the values in UTC. Depending on the local
  635.             // timezone and the values selected in datetimepicker the date in UTC
  636.             // might be shifted to the previous or next day.
  637.             // For example: The user (with local timezone GMT+05) selected 
  638.             // Feb 10 2006 00:00:00. The corresponding value in UTC is
  639.             // Feb 09 2006 19:00:00. If we now set isDate to true we end up with
  640.             // a date of Feb 09 2006 instead of Feb 10 2006 resulting in errors
  641.             // during the following comparison.
  642.             // Calling getInTimezone() ensures that we use the same dates as 
  643.             // displayed to the user in datetimepicker for comparison.
  644.             startDate = startDate.getInTimezone(kDefaultTimezone);
  645.             endDate = endDate.getInTimezone(kDefaultTimezone);
  646.             startDate.isDate = true;
  647.             endDate.isDate = true;
  648.         }
  649.     } else {
  650.         startDate = getElementValue("todo-has-entrydate", "checked") ? 
  651.             jsDateToDateTime(getElementValue("todo-entrydate")) : null;
  652.         endDate = getElementValue("todo-has-duedate", "checked") ? 
  653.             jsDateToDateTime(getElementValue("todo-duedate")) : null;
  654.         
  655.         var taskRepeatWarning = document.getElementById("task-repeat-warning");
  656.         if (!startDate && getElementValue("item-recurrence", "checked")) {
  657.             enableAccept = false;
  658.             taskRepeatWarning.removeAttribute("hidden");
  659.         } else {
  660.             taskRepeatWarning.setAttribute("hidden", "true");
  661.         }
  662.     }
  663.  
  664.     var timeWarning = document.getElementById("end-time-warning");
  665.     if (endDate && startDate && endDate.compare(startDate) == -1) {
  666.         enableAccept = false;
  667.         timeWarning.removeAttribute("hidden");
  668.     } else {
  669.         timeWarning.setAttribute("hidden", "true");
  670.     }
  671.  
  672.     // can't add/edit items in readOnly calendars
  673.     document.getElementById("read-only-item").setAttribute("hidden", !gReadOnlyMode);
  674.     var cal = document.getElementById("item-calendar").selectedItem.calendar;
  675.     document.getElementById("read-only-cal").setAttribute("hidden", 
  676.                                               !cal.readOnly);
  677.     if (gReadOnlyMode || cal.readOnly) {
  678.         enableAccept = false;
  679.     }
  680.  
  681.     if (cal.sendItipInvitations) {
  682.         enableElement("send-invitations-checkbox");
  683.     } else {
  684.         disableElement("send-invitations-checkbox");
  685.     }
  686.  
  687.     if (!updateTaskAlarmWarnings()) {
  688.         enableAccept = false;
  689.     }
  690.     
  691.     var acceptButton = document.getElementById("calendar-event-dialog").getButton("accept");
  692.     if (!enableAccept) {
  693.         acceptButton.setAttribute("disabled", "true");
  694.     } else if (acceptButton.getAttribute("disabled")) {
  695.         acceptButton.removeAttribute("disabled");
  696.     }
  697.     
  698.     return;
  699. }
  700.  
  701. function updateDueDate()
  702. {
  703.     if (!isToDo(window.calendarItem))
  704.         return;
  705.  
  706.     // force something to get set if there was nothing there before
  707.     setElementValue("todo-duedate", getElementValue("todo-duedate"));
  708.  
  709.     setElementValue("todo-duedate", !getElementValue("todo-has-duedate", "checked"), "disabled");
  710.     if (getElementValue("todo-has-entrydate", "checked") && getElementValue("todo-has-duedate", "checked")) {
  711.         var start = jsDateToDateTime(getElementValue("todo-entrydate"));
  712.         var end = jsDateToDateTime(getElementValue("todo-duedate"));
  713.         gItemDuration = end.subtractDate(start);
  714.     } else {
  715.         gItemDuration = null;
  716.     }
  717.  
  718.     updateAccept();
  719. }
  720.  
  721. function updateEntryDate()
  722. {
  723.     if (!isToDo(window.calendarItem))
  724.         return;
  725.  
  726.     // force something to get set if there was nothing there before
  727.     setElementValue("todo-entrydate", getElementValue("todo-entrydate"));
  728.  
  729.     setElementValue("todo-entrydate", !getElementValue("todo-has-entrydate", "checked"), "disabled");
  730.  
  731.     if (getElementValue("todo-has-entrydate", "checked") && getElementValue("todo-has-duedate", "checked")) {
  732.         var start = jsDateToDateTime(getElementValue("todo-entrydate"));
  733.         var end = jsDateToDateTime(getElementValue("todo-duedate"));
  734.         gItemDuration = end.subtractDate(start);
  735.     } else {
  736.         gItemDuration = null;
  737.     }
  738.  
  739.     updateAccept();
  740. }
  741.  
  742. function updateTaskAlarmWarnings() {
  743.     document.getElementById("alarm-warnings").setAttribute("hidden", true);
  744.     document.getElementById("alarm-start-warning").setAttribute("hidden", true);
  745.     document.getElementById("alarm-end-warning").setAttribute("hidden", true);
  746.  
  747.     var alarmType = getElementValue("item-alarm");
  748.     if (!isToDo(window.calendarItem) || alarmType == "none") {
  749.         return true;
  750.     }
  751.  
  752.     var hasEntryDate = getElementValue("todo-has-entrydate", "checked");
  753.     var hasDueDate = getElementValue("todo-has-duedate", "checked");
  754.  
  755.     var alarmRelated = document.getElementById("alarm-trigger-relation").selectedItem.value;
  756.  
  757.     if ((alarmType != "custom" || alarmRelated == "START") && !hasEntryDate) {
  758.         document.getElementById("alarm-warnings").removeAttribute("hidden");
  759.         document.getElementById("alarm-start-warning").removeAttribute("hidden");
  760.         return false;
  761.     }
  762.  
  763.     if (alarmRelated == "END" && !hasDueDate) {
  764.         document.getElementById("alarm-warnings").removeAttribute("hidden");
  765.         document.getElementById("alarm-end-warning").removeAttribute("hidden");
  766.         return false;
  767.     }
  768.  
  769.     return true;
  770. }
  771.  
  772. function updateAllDay()
  773. {
  774.     if (!isEvent(window.calendarItem))
  775.         return;
  776.  
  777.     var allDay = getElementValue("event-all-day", "checked");
  778.     setElementValue("event-starttime", allDay, "timepickerdisabled");
  779.     setElementValue("event-endtime", allDay, "timepickerdisabled");
  780.  
  781.     if (!allDay) {
  782.         // Reset default event length, if timepickers are equal
  783.         var startDate = jsDateToDateTime(getElementValue("event-starttime"));
  784.         var endDate = jsDateToDateTime(getElementValue("event-endtime"));
  785.         if (startDate.compare(endDate) == 0) {
  786.             endDate.minute += getPrefSafe("calendar.event.defaultlength", 60);
  787.             setElementValue("event-endtime", endDate.jsDate);
  788.         }
  789.     }
  790.  
  791.     updateAccept();
  792. }
  793.  
  794.  
  795. function updateRecurrence()
  796. {
  797.     var recur = getElementValue("item-recurrence", "checked");
  798.     if (recur) {
  799.         setElementValue("set-recurrence", false, "disabled");
  800.     } else {
  801.         setElementValue("set-recurrence", "true", "disabled");
  802.     }
  803.  
  804.     updateAccept();
  805. }
  806.  
  807. var prevAlarmItem = null;
  808. function setAlarmFields(alarmItem)
  809. {
  810.     var alarmLength = alarmItem.getAttribute("length");
  811.     if (alarmLength != "") {
  812.         var alarmUnits = alarmItem.getAttribute("unit");
  813.         var alarmRelation = alarmItem.getAttribute("relation");
  814.         setElementValue("alarm-length-field", alarmLength);
  815.         setElementValue("alarm-length-units", alarmUnits);
  816.         setElementValue("alarm-trigger-relation", alarmRelation);
  817.     }
  818. }
  819. function updateAlarm()
  820. {
  821.     var alarmMenu = document.getElementById("item-alarm");
  822.     var alarmItem = alarmMenu.selectedItem;
  823.  
  824.     var alarmItemValue = alarmItem.getAttribute("value");
  825.     switch (alarmItemValue) {
  826.     case "custom":
  827.         /* restore old values if they're around */
  828.         setAlarmFields(alarmItem);
  829.         
  830.         document.getElementById("alarm-details").removeAttribute("hidden");
  831.         break;
  832.     default:
  833.         var customItem = document.getElementById("alarm-custom-menuitem");
  834.         if (prevAlarmItem == customItem) {
  835.             customItem.setAttribute("length", getElementValue("alarm-length-field"));
  836.             customItem.setAttribute("unit", getElementValue("alarm-length-units"));
  837.             customItem.setAttribute("relation", getElementValue("alarm-trigger-relation"));
  838.         }
  839.         setAlarmFields(alarmItem);
  840.  
  841.         document.getElementById("alarm-details").setAttribute("hidden", true);
  842.         break;
  843.     }
  844.  
  845.     prevAlarmItem = alarmItem;
  846.     updateAccept();
  847.  
  848.     this.sizeToContent();
  849. }
  850.  
  851. function editRecurrence()
  852. {
  853.     var args = new Object();
  854.     args.calendarEvent = window.calendarItem;
  855.     args.recurrenceInfo = window.recurrenceInfo || args.calendarEvent.recurrenceInfo;
  856.  
  857.     var kDefaultTimezone = window.opener.calendarDefaultTimezone();
  858.     if (isEvent(window.calendarItem)) {
  859.         var startDate = jsDateToDateTime(getElementValue("event-starttime")).getInTimezone(kDefaultTimezone);
  860.         if (getElementValue("event-all-day", "checked")) {
  861.             startDate.isDate = true;
  862.         }
  863.         args.startDate = startDate;
  864.     } else if (isToDo(window.calendarItem)) {
  865.         if (!getElementValue("todo-has-entrydate", "checked")) {
  866.             return;
  867.         }
  868.         args.startDate = jsDateToDateTime(getElementValue("todo-entrydate")).getInTimezone(kDefaultTimezone);
  869.     }
  870.  
  871.     var savedWindow = window;
  872.     args.onOk = function(recurrenceInfo) {
  873.         savedWindow.recurrenceInfo = recurrenceInfo;
  874.     };
  875.  
  876.     // wait cursor will revert to auto in eventDialog.js loadCalendarEventDialog
  877.     window.setCursor("wait");
  878.  
  879.     // open the dialog modally
  880.     openDialog("chrome://calendar/content/calendar-recurrence-dialog.xul", "_blank", "chrome,titlebar,modal", args);
  881. }
  882.  
  883.  
  884.  
  885. /* utility functions */
  886. function setItemProperty(item, propertyName, value)
  887. {
  888.     switch(propertyName) {
  889.     case "startDate":
  890.         if (value.isDate && !item.startDate.isDate ||
  891.             !value.isDate && item.startDate.isDate ||
  892.             value.timezone != item.startDate.timezone ||
  893.             value.compare(item.startDate) != 0)
  894.             item.startDate = value;
  895.         break;
  896.     case "endDate":
  897.         if (value.isDate && !item.endDate.isDate ||
  898.             !value.isDate && item.endDate.isDate ||
  899.             value.timezone != item.endDate.timezone ||
  900.             value.compare(item.endDate) != 0)
  901.             item.endDate = value;
  902.         break;
  903.  
  904.     case "entryDate":
  905.         if (value == item.entryDate)
  906.             break;
  907.         if ((value && !item.entryDate) ||
  908.             (!value && item.entryDate) ||
  909.             (value.timezone != item.entryDate.timezone) ||
  910.             (value.compare(item.entryDate) != 0) ||
  911.             (value.isDate != item.entryDate.isDate))
  912.             item.entryDate = value;
  913.         break;
  914.     case "dueDate":
  915.         if (value == item.dueDate)
  916.             break;
  917.         if ((value && !item.dueDate) ||
  918.             (!value && item.dueDate) ||
  919.             (value.timezone != item.dueDate.timezone) ||
  920.             (value.compare(item.dueDate) != 0) ||
  921.             (value.isDate != item.dueDate.isDate))
  922.             item.dueDate = value;
  923.         break;
  924.     case "isCompleted":
  925.         if (value != item.isCompleted)
  926.             item.isCompleted = value;
  927.         break;
  928.  
  929.     case "title":
  930.         if (value != item.title)
  931.             item.title = value;
  932.         break;
  933.  
  934.     default:
  935.         if (!value || value == "")
  936.             item.deleteProperty(propertyName);
  937.         else if (item.getProperty(propertyName) != value)
  938.             item.setProperty(propertyName, value);
  939.         break;
  940.     }
  941. }
  942.  
  943. function toggleDetails() {
  944.     var detailsElements = document.getElementsByAttribute("details", "true");
  945.     var detailsButton = document.getElementById("calendar-event-dialog").getButton("disclosure");
  946.  
  947.     if (!detailsElements[0].collapsed) {
  948.         // Hide details
  949.         for each (elem in detailsElements) {
  950.             elem.collapsed = true;
  951.         }
  952.         detailsButton.setAttribute("label", moreLabel);
  953.         this.sizeToContent();
  954.         return;
  955.     }
  956.  
  957.     // Display details
  958.     for each (elem in detailsElements) {
  959.         elem.collapsed = false;
  960.     }
  961.     detailsButton.setAttribute("label", lessLabel);
  962.     this.sizeToContent();
  963.  
  964.     if (gDetailsShown) {
  965.         // Focus the description
  966.         document.getElementById("item-description").focus();
  967.  
  968.         // We've already loaded this stuff before, so we're done
  969.         return;
  970.     }
  971.  
  972.     loadDetails();
  973.  
  974.     // Now focus the description
  975.     document.getElementById("item-description").focus();
  976. }
  977.  
  978. function loadDetails() {
  979.     gDetailsShown = true;
  980.     var item = window.calendarItem;
  981.  
  982.     // Attendees
  983.     var attendeeListBox = document.getElementById("attendees-list");
  984.     attendeeListBox.attendees = item.getAttendees({});
  985.     var sendInvitesCheckbox = document.getElementById("send-invitations-checkbox");
  986.     if (item.hasProperty("X-MOZ-SEND-INVITATIONS")) {
  987.         sendInvitesCheckbox.checked = (item.getProperty("X-MOZ-SEND-INVITATIONS") == "TRUE");
  988.     } else {
  989.         sendInvitesCheckbox.checked = false;
  990.     }
  991.  
  992.     /* Status */
  993.     setElementValue("item-url",         item.getProperty("URL"));
  994.     setElementValue("item-description", item.getProperty("DESCRIPTION"));
  995.     if (isEvent(item)) {
  996.         setElementValue("event-status", item.getProperty("STATUS"));
  997.     } else {
  998.         setElementValue("todo-status", item.getProperty("STATUS"));
  999.     }
  1000.  
  1001.     /* Task completed date */
  1002.     if (item.completedDate) {
  1003.         updateToDoStatus(item.status, item.completedDate.jsDate);
  1004.     } else {
  1005.         updateToDoStatus(item.status);
  1006.     }
  1007.  
  1008.     /* Task percent complete */
  1009.     if (isToDo(item)) {
  1010.         var percentCompleteInteger = 0;
  1011.         var percentCompleteProperty = item.getProperty("PERCENT-COMPLETE");
  1012.         if (percentCompleteProperty != null) {
  1013.             percentCompleteInteger = parseInt(percentCompleteProperty);
  1014.         }
  1015.         if (percentCompleteInteger < 0) {
  1016.             percentCompleteInteger = 0;
  1017.         } else if (percentCompleteInteger > 100) {
  1018.             percentCompleteInteger = 100;
  1019.         }
  1020.         setElementValue("percent-complete-textbox", percentCompleteInteger);
  1021.     }
  1022.  
  1023.     /* Priority */
  1024.     var priorityInteger = parseInt(item.priority);
  1025.     if (priorityInteger >= 1 && priorityInteger <= 4) {
  1026.         document.getElementById("priority-levels").selectedIndex = 3; // high priority
  1027.     } else if (priorityInteger == 5) {
  1028.         document.getElementById("priority-levels").selectedIndex = 2; // medium priority
  1029.     } else if (priorityInteger >= 6 && priorityInteger <= 9) {
  1030.         document.getElementById("priority-levels").selectedIndex = 1; // low priority
  1031.     } else {
  1032.         document.getElementById("priority-levels").selectedIndex = 0; // not defined
  1033.     }
  1034.  
  1035.     /* Privacy */
  1036.     switch (item.privacy) {
  1037.         case "PUBLIC":
  1038.         case "PRIVATE":
  1039.         case "CONFIDENTIAL":
  1040.             setElementValue("privacy-menulist", item.privacy);
  1041.             break;
  1042.         case "":
  1043.             setElementValue("private-menulist", "PUBLIC");
  1044.             break;
  1045.         default:  // bogus value
  1046.             dump("ERROR! Event has invalid privacy string: " + item.privacy + "\n");
  1047.             break;
  1048.     }
  1049.  
  1050.     // update alarm checkbox/label/settings button
  1051.     updateAlarm();
  1052.  
  1053.     updateTaskAlarmWarnings();
  1054.  
  1055.     updateURL(item.getProperty("URL"));
  1056.     return;
  1057. }
  1058.  
  1059. function updateToDoStatus(status, passedInCompletedDate)
  1060. {
  1061.     // RFC2445 doesn't support completedDates without the todo's status
  1062.     // being "COMPLETED", however twiddling the status menulist shouldn't
  1063.     // destroy that information at this point (in case you change status
  1064.     // back to COMPLETED). When we go to store this VTODO as .ics the
  1065.     // date will get lost.
  1066.  
  1067.     var completedDate;
  1068.     if (passedInCompletedDate) {
  1069.         completedDate = passedInCompletedDate;
  1070.     } else {
  1071.         completedDate = null;
  1072.     }
  1073.  
  1074.     // remember the original values
  1075.     var oldPercentComplete = getElementValue("percent-complete-textbox");
  1076.     var oldCompletedDate   = getElementValue("completed-date-picker");
  1077.  
  1078.     switch (status) {
  1079.     case null:
  1080.     case "":
  1081.     case "NONE":
  1082.         document.getElementById("todo-status").selectedIndex = 0;
  1083.         disableElement("percent-complete-textbox");
  1084.         disableElement("percent-complete-label");
  1085.         break;
  1086.     case "CANCELLED":
  1087.         document.getElementById("todo-status").selectedIndex = 4;
  1088.         disableElement("percent-complete-textbox");
  1089.         disableElement("percent-complete-label");
  1090.         break;
  1091.     case "COMPLETED":
  1092.         document.getElementById("todo-status").selectedIndex = 3;
  1093.         enableElement("percent-complete-textbox");
  1094.         enableElement("percent-complete-label");
  1095.         // if there isn't a completedDate, set it to now
  1096.         if (!completedDate)
  1097.             completedDate = new Date();
  1098.         break;
  1099.     case "IN-PROCESS":
  1100.         document.getElementById("todo-status").selectedIndex = 2;
  1101.         disableElement("completed-date-picker");
  1102.         enableElement("percent-complete-textbox");
  1103.         enableElement("percent-complete-label");
  1104.         break;
  1105.     case "NEEDS-ACTION":
  1106.         document.getElementById("todo-status").selectedIndex = 1;
  1107.         enableElement("percent-complete-textbox");
  1108.         enableElement("percent-complete-label");
  1109.         break;
  1110.     }
  1111.  
  1112.     if (status == "COMPLETED") {
  1113.         setElementValue("percent-complete-textbox", "100");
  1114.         setElementValue("completed-date-picker", completedDate);
  1115.         enableElement("completed-date-picker");
  1116.     } else {
  1117.         if (oldPercentComplete != 100) {
  1118.             setElementValue("percent-complete-textbox", oldPercentComplete);
  1119.         } else {
  1120.             setElementValue("percent-complete-textbox", "");
  1121.         }
  1122.         setElementValue("completed-date-picker", oldCompletedDate);
  1123.         disableElement("completed-date-picker");
  1124.     }
  1125. }
  1126.  
  1127. function updateURL(aValue) 
  1128. {
  1129.     var button = document.getElementById("load-url-button");
  1130.     button.setAttribute("disabled", true)
  1131.  
  1132.     if (!aValue) {
  1133.         return;
  1134.     }
  1135.  
  1136.     // The user might have just put in 'www.foo.com', correct that here
  1137.     if (aValue.indexOf( ":" ) == -1) {
  1138.         aValue = "http://" + aValue;
  1139.     }
  1140.     try {
  1141.         makeURL(aValue);
  1142.         // If we made it this far, that means it's a valid url
  1143.         button.removeAttribute("disabled");
  1144.     } catch(ex) {}
  1145.  
  1146.     return;
  1147. }
  1148.  
  1149. function loadURL()
  1150. {
  1151.     var url = getElementValue("item-url");
  1152.  
  1153.     // The user might have just put in 'www.foo.com', correct that here
  1154.     if (url.indexOf( ":" ) == -1) {
  1155.        url = "http://" + url;
  1156.     }
  1157.  
  1158.     launchBrowser(url);
  1159.     return;
  1160. }
  1161.  
  1162. var gOldCatIndex = 0;
  1163. function categorySelect(aValue) {
  1164.     if (aValue != "##NEW") {
  1165.         gOldCatIndex = document.getElementById("item-categories").selectedIndex;
  1166.         return;
  1167.     }
  1168.  
  1169.     // Make sure we don't leave 'New..' selected if they hit cancel
  1170.     document.getElementById("item-categories").selectedIndex = gOldCatIndex;
  1171.  
  1172.     window.openDialog("chrome://calendar/content/preferences/editCategory.xul",
  1173.                       "addCategory", "modal,centerscreen,chrome,resizable=no",
  1174.                       "", null, calGetString("calendar", "addCategory"));
  1175. }
  1176.  
  1177. // Trick the dialog into thinking we're the categories pane
  1178. var gCategoriesPane = {
  1179.     saveCategory: function eventDialog_saveCategory(aName, aColor) {
  1180.         //Check to make sure another category doesn't have the same name
  1181.         var promptService = 
  1182.                  Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
  1183.                            .getService(Components.interfaces.nsIPromptService);
  1184.         var categoriesList = getPrefCategoriesArray();
  1185.         for each (cat in categoriesList) {
  1186.             if (aName.toLowerCase() == cat.toLowerCase()) {
  1187.                 var repTitle = calGetString("calendar", "categoryReplaceTitle");
  1188.                 var rep = calGetString("calendar", "categoryReplace");
  1189.                 if (promptService.confirm(null, repTitle, rep)) {
  1190.                     var categoryNameFix = formatStringForCSSRule(aName);
  1191.                     setPref("calendar.category.color." + categoryNameFix,
  1192.                             "CHAR",
  1193.                             aColor);
  1194.                 }
  1195.                 return;
  1196.             }
  1197.         }
  1198.  
  1199.         if (aName.length == 0) {
  1200.             promptService.alert(null, null, noBlankCategories);
  1201.             return;
  1202.         }
  1203.  
  1204.         categoriesList.push(aName);
  1205.         sortArrayByLocaleCollator(categoriesList);
  1206.  
  1207.         setPrefCategoriesFromArray(categoriesList);
  1208.  
  1209.         if (aColor) {
  1210.             var categoryNameFix = formatStringForCSSRule(aName);
  1211.             setPref("calendar.category.color." + categoryNameFix, "CHAR", aColor);
  1212.         }
  1213.         var catList = document.getElementById("item-categories");
  1214.         var index = categoriesList.indexOf(aName);
  1215.         catList.insertItemAt(index, aName, aName);
  1216.         catList.selectedIndex = index;
  1217.     }
  1218. };
  1219.  
  1220. // Make sure that an AUS update triggered restart doesn't automatically nuke
  1221. // what the user is working on
  1222. window.tryToClose = function calItemDialogAttemptClose() {
  1223.     var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
  1224.                                   .getService(Components.interfaces.nsIPromptService);
  1225.     return promptService.confirm(window,
  1226.                                  calGetString("calendar", "confirmCloseTitle"),
  1227.                                  calGetString("calendar", "confirmCloseText"));
  1228. }
  1229.